#include "pintos_thread.h"

// Forward declaration. This function is implemented in reaction-runner.c,
// but you needn't care what it does. Just be sure it's called when
// appropriate within reaction_o()/reaction_h().
void make_water();

struct reaction {
	// FILL ME IN
	int hnum;
	int onum;
	int hcombine;
	int ocombine;
	int h2o;
	struct lock *zuhe;
	struct condition *hh;
	struct condition *o;
};

void
reaction_init(struct reaction *reaction)
{
	// FILL ME IN
	reaction->hnum=0;
	reaction->onum=0;
	reaction->hcombine=0;
	reaction->ocombine=0;
	reaction->h2o=0;
	reaction->zuhe=(struct lock *)malloc(sizeof(struct lock));
	lock_init(reaction->zuhe);
	reaction->hh=(struct condition *)malloc(sizeof(struct condition));
	cond_init(reaction->hh);
	reaction->o=(struct condition *)malloc(sizeof(struct condition));
	cond_init(reaction->o);
}

void
reaction_h(struct reaction *reaction)
{
	// FILL ME IN
	lock_acquire(reaction->zuhe);
	reaction->hnum++;
	if (reaction->hnum>=2&&reaction->onum>=1)
	{
		cond_broadcast(reaction->hh,reaction->zuhe);
		cond_broadcast(reaction->o,reaction->zuhe);
	}
	while ((reaction->hnum<2||reaction->onum<1 )&&reaction->hcombine==2*reaction->h2o)
	{
		// cond_signal(reaction->o,reaction->zuhe);
		cond_wait(reaction->hh,reaction->zuhe);	
	}
	if (reaction->hnum>=2&&reaction->onum>=1&&reaction->hcombine==2*reaction->h2o)
	{
		make_water();
		reaction->hnum--;reaction->hnum--;
		reaction->onum--;
		reaction->h2o++;
	}
	reaction->hcombine++;
	lock_release(reaction->zuhe);
}

void
reaction_o(struct reaction *reaction)
{
	// FILL ME IN
	lock_acquire(reaction->zuhe);
	reaction->onum++;
	if (reaction->hnum>=2&&reaction->onum>=1)
	{
		cond_broadcast(reaction->hh,reaction->zuhe);
		cond_broadcast(reaction->o,reaction->zuhe);
	}
	while ((reaction->hnum<2||reaction->onum<1) &&reaction->ocombine==reaction->h2o)
	{
		// cond_signal(reaction->o,reaction->zuhe);
		cond_wait(reaction->o,reaction->zuhe);	
	}
	if (reaction->hnum>=2&&reaction->onum>=1&&reaction->ocombine==reaction->h2o)
	{
		make_water();
		reaction->hnum--;reaction->hnum--;
		reaction->onum--;
		reaction->h2o++;
	}
	reaction->ocombine++;
	lock_release(reaction->zuhe);
}
